package com.tianji.promotion.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.promotion.domain.dto.CouponFormDTO;
import com.tianji.promotion.domain.dto.CouponIssueFormDTO;
import com.tianji.promotion.domain.po.Coupon;
import com.tianji.promotion.domain.po.CouponScope;
import com.tianji.promotion.domain.po.UserCoupon;
import com.tianji.promotion.domain.vo.CouponPageVO;
import com.tianji.promotion.domain.vo.CouponVO;
import com.tianji.promotion.enums.CouponStatus;
import com.tianji.promotion.enums.ObtainType;
import com.tianji.promotion.enums.UserCouponStatus;
import com.tianji.promotion.mapper.CouponMapper;
import com.tianji.promotion.query.CouponQuery;
import com.tianji.promotion.service.ICouponService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.promotion.service.IExchangeCodeService;
import com.tianji.promotion.service.IUserCouponService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 优惠券的规则信息 服务实现类
 * </p>
 *
 * @author ltd
 * @since 2024-07-02
 */
@Service
@RequiredArgsConstructor
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements ICouponService {

    private final CouponScopeServiceImpl couponScopeService;

    private final IExchangeCodeService codeService;

    private final IUserCouponService userCouponService;

    @Override
    @Transactional
    public void addPromotion(CouponFormDTO couponFormDTO) {
        //新增优惠卷信息
        Coupon coupon = BeanUtil.toBean(couponFormDTO, Coupon.class);
        this.save(coupon);

        Boolean specific = couponFormDTO.getSpecific();
        if (!specific){
            return;
        }
        List<Long> scopes = couponFormDTO.getScopes();
        if (CollUtils.isEmpty(scopes)){
            throw new BizIllegalException("没有优惠卷范围");

        }
        List<CouponScope> couponScope = scopes.stream().map(bizId -> new CouponScope().setBizId(bizId).setCouponId(coupon.getId()))
                .collect(Collectors.toList());
        //新增优惠卷作用范围
        couponScopeService.saveBatch(couponScope);
    }

    @Override
    public PageDTO<CouponPageVO> queryCouponPage(CouponQuery couponQuery) {
        Page<Coupon> page = this.lambdaQuery()
                .eq(couponQuery.getType() != null, Coupon::getDiscountType, couponQuery.getType())
                .eq(couponQuery.getStatus() != null, Coupon::getStatus, couponQuery.getStatus())
                .like(StringUtils.isNotBlank(couponQuery.getName()), Coupon::getName, couponQuery.getName())
                .page(couponQuery.toMpPageDefaultSortByCreateTimeDesc());

        if (ObjectUtil.isEmpty(page)){
            return PageDTO.empty(page);
        }

        return PageDTO.of(page,CouponPageVO.class);
    }
    /**
     * 发放优惠卷
     * @param couponIssueFormDTO
     */
    @Override
    public void vouchersAreIssued(CouponIssueFormDTO couponIssueFormDTO) {
        //1.查询数据库优惠卷的数据
        Long id = couponIssueFormDTO.getId();
        Coupon coupon = this.getById(id);
        if (ObjectUtil.isEmpty(coupon)){
            throw new BadRequestException("查询优惠卷数据库失败！");
        }
        //2.判断优惠卷是否是有效时间发放的
        if (coupon.getStatus()!= CouponStatus.DRAFT&&coupon.getStatus()!=CouponStatus.PAUSE){
            throw new BizIllegalException("优惠卷状态错误");
        }
        //3.如果没有发放时间或发放开始时间在现在之前则修改状态为进行中
        LocalDateTime termBeginTime = couponIssueFormDTO.getTermBeginTime();
        LocalDateTime now = LocalDateTime.now();
        boolean issuneTime=termBeginTime==null|| !termBeginTime.isAfter(now);
        Coupon coupon1 = BeanUtil.toBean(couponIssueFormDTO, Coupon.class);


        if (issuneTime){
            coupon1.setStatus(CouponStatus.ISSUING);
            coupon1.setIssueBeginTime(now);
        }else {
            coupon1.setStatus(CouponStatus.UN_ISSUE);
        }
        updateById(coupon1);

        //判断优惠卷是否是换码，状态是待发放
        if (coupon.getObtainWay()== ObtainType.ISSUE&&coupon.getStatus()==CouponStatus.DRAFT){
            coupon.setIssueEndTime(coupon1.getIssueEndTime());
            codeService.asyncGenerateCode(coupon);

        }
    }

    @Override
    public List<CouponVO> queryCouponsList() {
        //1.查询发放中并且手动领取优惠卷的数据
        List<Coupon> couponsList = this.lambdaQuery()
                .eq(Coupon::getStatus, CouponStatus.ISSUING)
                .eq(Coupon::getObtainWay, ObtainType.PUBLIC)
                .list();
        if (CollUtils.isEmpty(couponsList)){
            return ListUtil.empty();
        }

        //2.获取用户id,优惠卷的id
        Long userId = UserContext.getUser();
        List<Long> couponId = couponsList.stream().map(coupon -> coupon.getId()).collect(Collectors.toList());
        //3.是否已领取 判断用户领取的优惠卷使用中数量，如果有则是领取，没有则
        //3.1首先查询用户里所有的优惠卷
        List<UserCoupon> userCoupons = userCouponService.lambdaQuery()
                .eq(UserCoupon::getUserId, userId)
                .in(UserCoupon::getCouponId,couponId)
                .list();
        //3.2获取用户未使用的数量
        Map<Long, Long> issueCount = userCoupons.stream().filter(userCoupon -> userCoupon.getStatus() == UserCouponStatus.UNUSED)
                .collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));


        //是否已可领取 判断用户领取优惠卷的数量是否是等于优惠卷最大领取的总数量
        Map<Long, Long> totalNumberOfUsers = userCoupons.stream().collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));


        //封装Vo
        List<CouponVO> couponVOS = new ArrayList<>(couponsList.size());
        for (Coupon coupon : couponsList) {
            //转vo
            CouponVO couponVO = BeanUtil.toBean(coupon, CouponVO.class);

            //获取优惠卷id
            Long id = couponVO.getId();
            //是否可领取，如果优惠卷已发行数量小于发行的总数量并且用户领取的优惠卷数量小于优惠卷本身最大限领数量则可以领取
            couponVO.setAvailable(coupon.getIssueNum()<coupon.getTotalNum()&&
                    totalNumberOfUsers.getOrDefault(id,0L)<coupon.getUserLimit());
          couponVO.setReceived(issueCount.getOrDefault(id,0L)>0);

          couponVOS.add(couponVO);
        }

        return couponVOS;
    }
}
